{% extends 'base.html' %} {% block title %}知识图谱{% endblock %} {% block
styles %}
<style>
  .node {
    fill: #ccc;
    stroke: #fff;
    stroke-width: 2px;
  }

  .node text {
    font-size: 12px;
    fill: #000;
    text-anchor: middle;
    dominant-baseline: central;
  }

  .link {
    stroke: #999;
    stroke-opacity: 0.6;
  }
</style>
{% endblock %} {% block content %}
<div class="container">
  <h1>知识图谱</h1>
  <div id="knowledge-graph"></div>

  <div class="search-box">
    <input type="text" id="search-input" placeholder="输入概念名称" />
    <button id="search-btn">搜索</button>
  </div>

  <div id="concept-details">
    <h2>概念详情</h2>
    <p id="concept-name"></p>
    <p id="concept-description"></p>
  </div>
</div>
{% endblock %} {% block scripts %}
<script src="https://d3js.org/d3.v6.min.js"></script>
<script>
  const graphData = {{ knowledge_graph_data | tojson }};

  const width = 800;
  const height = 600;

  const svg = d3.select("#knowledge-graph")
    .append("svg")
    .attr("width", width)
    .attr("height", height);

  const simulation = d3.forceSimulation(graphData.nodes)
    .force("link", d3.forceLink(graphData.links).id(d => d.id))
    .force("charge", d3.forceManyBody().strength(-100))
    .force("center", d3.forceCenter(width / 2, height / 2));

  const link = svg.append("g")
    .selectAll("line")
    .data(graphData.links)
    .join("line")
    .attr("class", "link");

  const node = svg.append("g")
    .selectAll("g")
    .data(graphData.nodes)
    .join("g")
    .call(drag(simulation));

  node.append("circle")
    .attr("r", 20)
    .attr("class", "node");

  node.append("text")
    .text(d => d.name);

  simulation.on("tick", () => {
    link
      .attr("x1", d => d.source.x)
      .attr("y1", d => d.source.y)
      .attr("x2", d => d.target.x)
      .attr("y2", d => d.target.y);

    node
      .attr("transform", d => `translate(${d.x},${d.y})`);
  });

  function drag(simulation) {
    function dragstarted(event) {
      if (!event.active) simulation.alphaTarget(0.3).restart();
      event.subject.fx = event.subject.x;
      event.subject.fy = event.subject.y;
    }

    function dragged(event) {
      event.subject.fx = event.x;
      event.subject.fy = event.y;
    }

    function dragended(event) {
      if (!event.active) simulation.alphaTarget(0);
      event.subject.fx = null;
      event.subject.fy = null;
    }

    return d3.drag()
      .on("start", dragstarted)
      .on("drag", dragged)
      .on("end", dragended);
  }

  const searchBtn = document.getElementById("search-btn");
  const searchInput = document.getElementById("search-input");
  const conceptName = document.getElementById("concept-name");
  const conceptDescription = document.getElementById("concept-description");

  searchBtn.addEventListener("click", () => {
    const keyword = searchInput.value.trim();
    if (keyword !== "") {
      fetch(`/knowledge_graph/concept/${keyword}`)
        .then(response => response.json())
        .then(data => {
          if (data.name && data.description) {
            conceptName.textContent = data.name;
            conceptDescription.textContent = data.description;
          } else {
            conceptName.textContent = "";
            conceptDescription.textContent = "概念未找到";
          }
        })
        .catch(error => {
          console.error("Error:", error);
          conceptName.textContent = "";
          conceptDescription.textContent = "获取概念详情时出错";
        });
    }
  });
</script>
{% endblock %}
